new function ()
{
    try 
    {
        Parent.implement
        (
            {
                property: 'property'
            }
           
        ,   function method () 
            {
                return true;
            }
        );
        
        function Parent () {;};
        

        Child.inherit(Parent);
        function Child () 
        {
            Parent.call(this);
        };   
    }
    catch (thrown) 
    {
        alert('Error applying extensions. Is the script pointing to the correct resource?' + thrown);
        if (thrown.stack)
            console.log(thrown.stack);
    }
 
    
    var tests= 
    [
        /**
         * tests for the presence of all the function extensions
         * in obkit core on an anonymous function.
         * @throws
         */
        function testExtendedMethodsPresent () 
        {
            var methods= 
            [
                'implementStatic', // define properties on a constructor
                'implement',       // define properties on a constructors prototype
                'getName',         // determine a functions name
                'bind',            // curry a function, bind its execution scope, or both
                'inherit',        // make one constructor inherit from another
                'is'               // determine if a value is an object instantiated by a specific constructor
            ]
            ,   subject= new Function;
            
            for (var i= 0, n= methods.length; i < n; i++) 
            {
                var name= methods[i];
                if ('function' !== typeof subject[name])
                    throw new Error ('Method not implemented! ' + name);
            }
        }
        
        /**
         * Function.prototype.inherit must be passed a constructor that
         * is not itself in order to work.
         */
    ,   function testInheritance () 
        {

            
            var child= new Child
            ,   parent= child.parent
            ,   constructor= child.constructor
            ,   property= child.property
            ,   method= child.method;
            
            if (parent !== Parent.prototype)
                throw 'Child.prototype.parent incorrectly set: ' + parent;
                
            if (constructor !== Child)
                throw 'Child.prototype.constructor incorrectly set: ' + constructor
            
            if (!('property' === property && property === Parent.prototype.property))
                throw 'Child.prototype.property not inherited';
                
            if (!('function' === typeof method && method === Parent.prototype.method))
                throw 'Child.prototype.method not inherited';
                
            if (!(child instanceof Parent))
                throw 'Child is not an instance of parent';
                
            if (!(Parent.prototype.isPrototypeOf(child)))
                throw 'Parent is not a superclass of child';
                
            function Mixin () {;};    
            
            try 
            {
                var result= Mixin.inherit(Mixin);
                throw 'Mixin should not have been able to inherit from itself';                 
            }
            catch (thrown) 
            {
                if (!thrown instanceof TypeError)
                    throw 'A type error should have been thrown by Mixin inheriting itself';                
            }
                
           
            
            try 
            {
                var result= Mixin.inherit(null);
                throw 'Mixin should not have been able to inherit from a non-function';
            }
            catch (thrown) 
            {
                ;
            }
                

                
            function A () {;};
            
            var result= Mixin.inherit(A);
            
            if (Mixin !== result)
                throw 'Mixin should have returned a reference to itslef after inheriting';
        }
        
        /**
         * Type and is both return false for the primitive value types null and
         * undefined. For the primitive types number, boolean and string, the
         * methods elide the distinction between primitives and objects (as does
         * JavaScript when it autocasts primitives to values!).
         * 
         */
    ,   function testTypeAndIs () 
        {
            var Constructor= String
            ,   string= 'value';
            
            if (!String.is(string))
                throw "string primitive is not an instanceof String"
            
            if (!(String.is(new String)))
                throw 'string object is not an instanceof String';
            
            if (!Child.is(new Child))
                throw 'child should be instance of Child'
                
            if (true !== Parent.is(new Child))
                throw 'child is not Parent'
            
            if (!Parent.is(new Child))
                throw 'child should be instance of parent';
        }
        
    ,   function testImplementStatic () 
        {
            
            var reference= Singleton.implementStatic
            (
                {
                    instance: null
                }
            
            ,   function getInstance () 
                {
                    if (this.is(this.instance))
                        return this.instance;
                    
                    return this.instance= new this;
                }
            );
            
            function Singleton () 
            {
                if (this.constructor.instance)
                    throw new Error ("Singleton already instantiated");
            };
            
            if (Singleton !== reference)
                throw 'Singleton should have returned a reference to itself after inheritStatic'
            
            if (false === Function.is(Singleton.getInstance))
                throw "Singleton.getInstance was not implemented";
                
            if (false === 'instance' in Singleton)
                throw "Singleton.instance property was not implemented";
                
            var instance= Singleton.getInstance();
            
            if (false === Singleton.is(instance))
                throw "Singleton type failure";

            var error;
            try 
            {
                new Singleton;
            }
            catch (thrown) 
            {
                error= thrown;
            }
            
            if (false === Error.is(error))
                throw 'Singleton.instance was not applied: ' + Singleton.instance;
        }
        
        /**
         * Test the implement method. This method accepts any number of objects,
         * each of which will be shallow copied to the constructors prototype. If
         * named functions are provided, their names will be inspected and they
         * will be added to the prototype by that name.
         * 
         * Anonymous functions and null and undefined values are ignored
         */
    ,   function testImplement () 
        {
            Abstract.implement
            (
                function abstractMethod () 
                {
                    ;
                }
            
            );
            
            function Abstract () 
            {
                ;
            };
            
            
            var reference= Subject.implement
            (
                Abstract.prototype 
            ,   function x () {;}
            );
            
            function Subject () {;};
            
            
            if (reference !== Subject)
                throw 'Subject should have returned a reference to itself after implement';
                
            if (Abstract.prototype.abstractMethod !== Subject.prototype.abstractMethod)
                throw 'Subject should have treated another constructors prototype as a plain traits object'
                
            var instance= new Subject;
            
            if (true === Abstract.is(instance))
                throw 'Subject should have been considered an instance of Abstract';
                
            if ('function' !== typeof instance.x)
                throw 'Subject instance should have implemented a method named x';
        }
        
        /**
         * You can use preventOverride to control whether or not members will
         * be overridden or not while using implement or implementStatic
         */
    ,   function testPreventOverride () 
        {
            

            if (false !== Mixin.implement.preventOverride)
                throw 'Default preventOverride settings were not applied'
                
                
            var firstTraits= 
                {
                    member: new Function
                }
            
            ,   secondTraits= 
                {
                    member: new String    
                }
            
            Mixin.implement(firstTraits);
            function Mixin () {;};
            
            if (false === 'member' in Mixin.prototype)
                throw 'Member was not implemented on Mixin';
                
            if (Mixin.implement !== Function.prototype.implement)
                throw 'Unexpected prototypal behaviour';
                
             
            
            Mixin.implement.preventOverride= true;
            Mixin.implement(secondTraits);
            
            if (secondTraits.member === Mixin.prototype.member)
                throw 'Member was overridden and should not have been';
                
            if (true === Mixin.implement.preventOverride)
                throw 'Default preventOverride settings were not reapplied!';
            
            Mixin.implement.preventOverride= false;
            Mixin.implement(secondTraits);
            
            if (secondTraits.member !== Mixin.prototype.member)
                throw 'Member was not overridden and should have been';
                
            Mixin.implementStatic(firstTraits);
            
            if (Mixin.member !== firstTraits.member)
                throw 'Member was not implemented on the constructor';
            
          
            Mixin.implement.preventOverride= true;
            Mixin.implementStatic(secondTraits);
            
            
            if (Mixin.member !== firstTraits.member)
                throw 'Member was overridden on the constructor and should not have been';
            
            
            Mixin.implement.preventOverride= false;
            Mixin.implementStatic(secondTraits);
            
            if (Mixin.member !== secondTraits.member)
                throw 'Member was not overridden on the constructor and should have been';
        }    


    ,   function testBind () 
        {
            
            var firstScope= 
                {
                    value: new Number
                }
                
            ,   secondScope= 
                {
                    value: new Object
                }
                
            ,   argument= new RegExp
                
            ,   firstBound= bound.bind(firstScope)
            ,   secondBound= bound.bind(secondScope)
            ,   argBound= curried.bind(null, argument)
                
            function bound () 
            {
                return this.value;
            };
            
            function curried (value) 
            {
                return value;
            };
            
            if (firstScope.value !== firstBound())
                throw "Scope was not bound to first scope";
                
            if (secondScope.value !== secondBound())
                throw "Scope was not bound to second scope";
            
            if (argument !== argBound())
                throw "function wasn't curried with argument";
        }
        
    ,   function testDefer () 
        {
            var shortInterval= 10
            ,   longInterval= 30
            ,   variable= null
            ,   value= new Object
            
            function shortDeferred () 
            {
                console.log('deferred1 executed');
                variable= value;
               
            }
            
            var deferred= shortDeferred.defer(shortInterval)
            setTimeout(function ()
            {
                console.log('verifier1 executed');    
                if (value !== variable)
                    throw "The function was not deferred";
            }, longInterval)
            
            
            var shortInterval2= 50
            ,   longInterval2= 100
            ,   scope= 
                {
                    field: new Object
                }
            ,   updatedScope= null    
                
            
            function d2 () 
            {
                console.log('deferred2 executed');
                updatedScope= this.field; // 'this' should refer to scope
            };
            
            var deferred= d2.defer(shortInterval2, scope);
            setTimeout(function ()
            {
                console.log('verifier2 executed');
                if (updatedScope !== scope.field)
                    throw "The deferred function scope was not set correctly";
                
            }, longInterval2);
            
            
            var t1= 80
            ,   t2= 200
            ,   value= 'somevalue';
            
            function d3 (argument) 
            {
                console.log('deferred3 executed');
                this.value= argument;
            }
            
            var deferred= d3.defer(t1, null, value);
            setTimeout(function () 
            {
                 console.log('verifier3 executed');
                if (window.value !== value)
                    throw "deferred argument was not appied to the window";
            }, t2);
        }   
        
        /**
         * 
         */
    ,   function testDeferObject () 
        {
            var argument= new Object
            ,   putValue
            ,   executeStatus
            ,   executeScope
            ,   executeResult
            ,   executeFault
            ,   executeInvoked= false
            ,   returnValue= new Object
            ,   lambda= function (arg) 
                {
                    putValue= arg;
                    return returnValue;
                }
                
            ,   t1= 50
            ,   t2= 100
            ,   t3= 200
            
            
            ,   deferred= lambda.defer(t1, null, argument);
            
            deferred.onExecute= function (status) 
            {
                executeScope= this;
                executeStatus= status;
                executeInvoked= true;
                executeResult= this.result;
                executeFault= this.fault;
            };
            
            
            if (deferred.interval !== t1)
                throw 'The interval property was not set correctly';
            
            if (false !== deferred.hasExecuted)
                throw 'The hasExecuted property should have been false'
            
            // test immediate execution
            deferred.execute();
                
            if (!deferred.hasExecuted)
                throw 'The deferred object should have shown the function to have executed'
            
            if (!executeInvoked)
                throw 'The onExecute method was not invoked';
            
            if (executeScope !== deferred)
                throw 'The onExecute function did not execute in the expected scope'
            
            if (!executeStatus)
                throw 'The execution status should have been true: ' + executeStatus
                
            if (putValue !== argument)
                throw 'The deferred function did not execute as expected';
                
            if (executeResult !== returnValue)
                throw 'The deferred object result property was not set correctly: ' + executeResult;
            
            if (null != executeFault)
                throw 'The deferred object fault property should not have been set';
                
            if ('undefined' !== typeof deferred.timeoutId)
                throw 'The timeoutId should have been deleted';    
            
            
            putValue= executeInvoked= executeScope= executeStatus= executeResult= executeFault= null;
            
            var fault= new Object
            ,   error
            ,   deferred2= null
            ,   willThrowFault= function () 
                {
                    throw fault;
                }

            deferred2= willThrowFault.defer(t1);
            
            if (deferred2 === deferred)
                throw 'A new deferred object was expected';
                
            deferred2.onExecute= function (status) 
            {
                executeInvoked= true;
                executionStatus= status;
                executionScope= this;
                executionResult= this.result;
                executionFault= this.fault;
            }
            
            // immediate execution
            try 
            {
                deferred2.execute();
            }
            catch (thrown) 
            {
                error= thrown;
            }
            
            
            if ('undefined' !== typeof error)
                throw 'Though a fault was encountered, the error should not have propagated';
            
            if (!executeInvoked)
                throw 'The deferred function should have been invoked';
                
            if (!deferred2.hasExecuted)
                throw 'The deferred function hasExecuted property should be true';
            
            if (false !== executionStatus)
                throw 'The deferred function fault should have been registered';
                
            if (null != executionResult)
                throw 'There should have been no execution result';
                
            if (fault !== executionFault)
                throw 'The deferred function fault should have matched';
            
            
            var expected= new Object
            ,   provided
            ,   executedOk= false
            ,   t3= 80
            ,   t4= 1000
            ,   d3= function (p) 
                {
                    provided= p;
                };
            
            var deferred= d3.defer(t3, null, expected);
            deferred.onExecute= function (status) 
            {
                executedOk= status;
                console.log('d3.onExecute');
            };
            
            setTimeout(function ()
            {
                console.log('verifier4 executed');
                if (expected != provided)
                    throw 'The deferred function did not assign expected values';
                    
                if (true !== executedOk)
                    throw 'The deferred function did not execute normally';
                    
                if (!deferred.hasExecuted)
                    throw 'the deferred function did not set hasExecuted'
                    
            },  t4);
            
            
        }
        
    ,   function testGetName () 
        {
           
           function method () {};
           
           if ('method' !== method.getName())
               throw 'Could not read name of method';
           
           var name= new Function().getName();    
           if ('anonymous' !== name)
               throw 'Expected "anonymous" as name of function but got ' + name;
           
           
        } 
        
        
        /* The following tests apply to extensions/Function */
        
    ,   function testFunctionLike ()
        {
            
            Map.implement
            (
            
                function has () {;}
                
            ,   function put () {;}
                
            ,   function get () {;}
            
            ,   function remove () {;}
            
            ,   function contains () {;}
            
            );
            
            function Map () {;};
            
            var object= 
            {
                has: function () {;}
                
            ,   put: function () {;}
            
            ,   get: function () {;}
             
            ,   remove: function () {;}
              
            ,   contains: function () {;}
            };
            
            if (false === Map.like(object))
                throw 'The object should have resembled a map!';
                
            delete object.contains;
            
            if (true === Map.like(object))
                throw 'The object should not have resembled a map!';
        }
        
    ,   function testFunctionIsSuperclassOf () 
        {
            
            function A () {;};
            
            B.inherit(A);
            function B () {;};
            
            if (false === A.isSuperclassOf(B))
                throw 'A should have been a superclass of B';
        }
        
    ,   function testFunctionIsSubclassOf () 
        {
            
            function A () {;};
            
            B.inherit(A);
            function B () {;};
            
            if (false === B.isSubclassOf(A))
                throw 'A should have been a subclass of B';
                
             
        }
    ];
    
    
    for (var i= 0, n= tests.length; i < n; i++) 
    {
        try 
        {
            var test= tests[i];
            test();
        }
        catch (thrown) 
        {
            console.log('test failed: ' + test.name + ' \n' + thrown);
            if (thrown.stack)
                console.log(thrown.stack);
        }  
    };    
};
